package com.cs.dingdingauto.extent

import android.annotation.SuppressLint
import android.app.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.Cursor
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.util.Log
import android.util.SparseArray
import androidx.core.app.NotificationManagerCompat
import androidx.core.util.forEach
import androidx.core.util.isEmpty
import com.cs.dingdingauto.bgs.Machine
import com.cs.dingdingauto.bgs.PendingIntentUtils
import com.cs.dingdingauto.bgs.Reflection
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.LinkedHashMap

@SuppressLint("StaticFieldLeak")
object ExternalActivityUtil : BroadcastReceiver(), Application.ActivityLifecycleCallbacks {

    const val TAG = "ExternalActivityUtil"
    private const val ACTION = ".ACTION_CHECK_PENDING_ACTIVITY"
    private const val MAX_RETRY = 5
    private const val RETRY_INTERVAL = 60 * 1000L
    private const val PROCESS_TIMEOUT = 15 * 1000L

    private var curRequestCode = 10001

    private var baseContext: Context? = null
    private val pendingBeans = LinkedHashMap<Int, PendingActivityBean>()

    private val handler = Handler(Looper.getMainLooper())
    private lateinit var alarmManager: AlarmManager
    private lateinit var pollerAction: String
    private lateinit var pollerPendingIntent: PendingIntent
    private val activityMap = SparseArray<Class<out Activity>>()
    private var isRetryStrategyEnable = false
    private var allowPopupOnActivities: ArrayList<Class<out Activity>>? = null
    private var isStartActivityWithNewApi: Boolean = false
    private var isKeepAliveSdkAvailable: Boolean? = null
    private var isStatisticEnable = false

    @JvmStatic
    fun attachBaseContext(baseContext: Context, application: Application, isRetryStrategyEnable: Boolean) {
        Log.i(TAG, "attachBaseContext: SDK_INT : ${Build.VERSION.SDK_INT} ")
        ExternalActivityUtil.baseContext = baseContext
        Reflection.unseal(baseContext)
        ExternalActivityUtil.isRetryStrategyEnable = isRetryStrategyEnable
        alarmManager = baseContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        if (isRetryStrategyEnable) {
            application.registerActivityLifecycleCallbacks(this)
            initReceiver(baseContext)
        }
    }
    var popupCallback: IPopupCallback? = null

    @JvmStatic
    fun setupAllowPopupOnActivities(vararg classes: Class<out Activity>) {
        allowPopupOnActivities = arrayListOf()
        allowPopupOnActivities!!.addAll(classes)
    }

    @JvmStatic
    fun setStartActivityWithNewApiEnable(enable: Boolean) {
        isStartActivityWithNewApi = enable
    }

    @JvmStatic
    fun setStatisticEnable(enable: Boolean) {
        isStatisticEnable = enable
    }

    @JvmStatic
    fun isStatisticEnable(): Boolean {
        return isStatisticEnable
    }

    private fun initReceiver(context: Context) {

        pollerAction = context.packageName + ACTION
        val intentFilter = IntentFilter()
        intentFilter.addAction(pollerAction)
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF)
        intentFilter.addAction(Intent.ACTION_USER_PRESENT)
        context.registerReceiver(this, intentFilter)
        pollerPendingIntent =
            PendingIntentUtils.getBroadcast(context, 10000, Intent(pollerAction), PendingIntent.FLAG_UPDATE_CURRENT)
    }

    private fun startPoller() {
//        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60 * 1000L, pollerPendingIntent)
        triggerAlarm(System.currentTimeMillis() + RETRY_INTERVAL, pollerPendingIntent)
    }

    private fun stopPoller() {
        alarmManager.cancel(pollerPendingIntent)
    }

    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            pollerAction -> {
                if (allowPopupOn()) {
                    if (areAllPendingActivitiesTimeout()) {
                        Log.i(TAG, "检查PendingActivity")
                        checkPendingActivityByContext(context)
                    } else {
                        Log.i(TAG, "有Activity正在等待启动，忽略这次检查")
                    }
                } else {
                    Log.i(TAG, "当前Activity不允许弹窗，忽略这次检查")
                }
            }
            Intent.ACTION_SCREEN_OFF -> stopPoller()
            Intent.ACTION_USER_PRESENT -> startPoller()
        }
    }

    private fun allowPopupOn(): Boolean {
        if (activityMap.isEmpty()) {
            return true
        }
        if (allowPopupOnActivities != null) {
            activityMap.forEach { _, value ->
                var isContained = false
                run breaking@{
                    allowPopupOnActivities!!.forEach { allowAct ->
                        if (allowAct == value) {
                            isContained = true
                            return@breaking
                        }
                    }
                }
                if (!isContained) {
                    return false
                }
            }
            return true
        } else {
            return false
        }
    }

    private fun areAllPendingActivitiesTimeout(ignore: Int? = null): Boolean {
        val now = System.currentTimeMillis()
        pendingBeans.entries.forEach { entry ->
            val requestCode = entry.key
            val bean = entry.value
            if (requestCode != ignore && bean.startProcessingTime != -1L &&  now - bean.startProcessingTime < PROCESS_TIMEOUT) {
                Log.i(TAG, "Activity ${requestCode}等待启动 -- now: ${Date(now)}, startProcessingTime: ${Date(bean.startProcessingTime)}")
                return false
            }
        }
        return true
    }

    /**
     * 当前应用的工作流完成，允许触发下一个弹窗
     */
    @JvmStatic
    fun onAppCurrentWorkflowOver(activity: Activity) {
        checkPendingActivityByContext(activity)
    }

    private fun checkPendingActivityByContext(context: Context) {
        Log.i(TAG, "checkPendingActivity - context: ${context.javaClass.simpleName}")
        if (pendingBeans.isNotEmpty()) {
            val entry = pendingBeans.entries.iterator().next()
            val requestCode = entry.key
            val bean = entry.value
            val now = System.currentTimeMillis()
            if (context is Activity || bean.startProcessingTime != -1L || now - bean.startProcessingTime >= PROCESS_TIMEOUT) {
                doStartActivity(context, requestCode, bean.intent!!)
                bean.startProcessingTime = now
                bean.retryCount++
                if (bean.retryCount >= MAX_RETRY) {
                    pendingBeans.remove(requestCode)
                    Log.i(TAG, "RequestCode: ${requestCode}, retryCount大于等于${MAX_RETRY}，从队列中删除")
                }
            } else {
                Log.i(TAG, "RequestCode: ${requestCode}, 距离上次触发时间小于$PROCESS_TIMEOUT")
            }
        } else {
            Log.i(TAG, "队列中没有等待的RequestCode")
        }
    }

    @JvmStatic
    internal fun onActivityCreated(requestCode: Int) {
        pendingBeans.remove(requestCode)
        Log.i(TAG, "onActivityCreated: $requestCode")
    }

    @JvmStatic
    fun startActivity(context: Context, intent: Intent) {
        popupCallback?.onPopupTouch()
        val requestCode = curRequestCode
        Log.i(TAG, "startActivity, requestCode: ${requestCode}, intent: ${intent.toUri(0)}")
        curRequestCode++
        if (isRetryStrategyEnable) {
            val pendingBean = PendingActivityBean().apply {
                this.intent = intent
            }
            pendingBeans[requestCode] = pendingBean
            if (context is Activity) {
                pendingBean.startProcessingTime = System.currentTimeMillis()
                doStartActivity(context, requestCode, intent)
            } else {
                val allowPopupOn = allowPopupOn()
                val areAllPendingActivitiesTimeout = areAllPendingActivitiesTimeout(requestCode)
                Log.i(TAG,
                    "allowPopupOn: ${allowPopupOn}, areAllPendingActivitiesTimeout: ${areAllPendingActivitiesTimeout}")
                val isHandleIntent = allowPopupOn && areAllPendingActivitiesTimeout
                if (isHandleIntent) {
                    pendingBean.startProcessingTime = System.currentTimeMillis()
                    doStartActivity(context, requestCode, intent)
                }
            }
        } else {
            doStartActivity(context, requestCode, intent)
        }
    }

    @SuppressLint("WrongConstant")
    private fun doStartActivity(context: Context, requestCode: Int, intent: Intent) {
        intent.putExtra(ExternalActivity.KEY_REQUEST_CODE, requestCode)
        if (context is Activity) {
            Log.i(TAG, "RequestCode: $requestCode - doStartActivity, 直接使用当前Activity拉起")
            intent.putExtra(ExternalActivity.KEY_FORCE_START, true)
            try {
                context.startActivity(intent)
                return
            } catch (e: Exception) {
                //Do nothing
            }
        }
        if (isStartActivityWithNewApi && isKeepAliveSdkAvailable == null) {
            isKeepAliveSdkAvailable = try {
                Class.forName("com.dcm.keepalive.alive.v2.Alive2Entry")
                true
            } catch (t: Throwable) {
                false
            }
        }
        if (Build.VERSION.SDK_INT >= 26 && isKeepAliveSdkAvailable == true) {
            Log.i(TAG, "使用新的API打开")
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
//            IntentUtils.startActivityNew(intent)
        } else {
            Log.i(TAG, "使用旧的API打开")
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            intent.addFlags(1082130432)
            if (Settings.canDrawOverlays(context)) {
                context.startActivity(intent)
            }
            val isHandle = when {
                Machine.isXiaomi() -> {
                    reflectMiIntent(intent)
                    if (Build.VERSION.SDK_INT < 29) {
                        startActivityBelowQ(intent)
                    } else {
                        false
                    }
                }
                Machine.isVivo() -> {
                    reflectVivoIntent(intent)
                    if (Build.VERSION.SDK_INT < 29) {
                        startActivityBelowQ(intent)
                    } else {
                        false
                    }
                }
                (Machine.isHuaWei() && Build.VERSION.SDK_INT < 27) -> {
                    context.startActivity(intent)
                    true
                }
                else -> {
                    false
                }
            }
            if (!isHandle) {
                startNotification(context, requestCode, intent, 0)
            }
        }
    }

    private fun startNotification(context: Context, requestCode: Int, intent: Intent, delayTime: Long) {
        val pendingIntent =
            PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        if (Build.VERSION.SDK_INT >= 29 && Machine.isVivo() && isNotificationEnable(context)) {
            ExternalNotifyUtil.sendNotify(context, pendingIntent)
            return
        }
        if (Build.VERSION.SDK_INT >= 29) {
            try {
//                alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 200, pendingIntent)
//                Log.i("TripleM", "alarmManager.setExact")
//                if (!checkAllowedBgPopupPermission(context)) {
//                    context.startActivity(intent)
//                    Log.i("TripleM", "context.startActivity")
//                }

                val now = System.currentTimeMillis()
                val delay = if (Machine.isHarmonyOS()) 0L else 5000L
                triggerAlarm(now + delay, pendingIntent)
                if (delay > 0L && (Machine.isVivo() || (Machine.isXiaomi() && Build.VERSION.SDK_INT >= 30))) {
                    //vivo的android10、11和小米的android11使用pendingIntent + 下拉通知栏，可以100%打开
                    handler.postDelayed({
//                        WindowUtils.expandNotification(context)
                    }, delay - 300L)
                }
                ExternalNotifyUtil.sendNotify(context, pendingIntent)
            } catch (unused: Exception) {
                unused.printStackTrace()
            }
        } else {
            handler.postDelayed({
                var send = false
                try {
                    pendingIntent.send()
                    send = true
                } catch (unused: Exception) {
                    unused.printStackTrace()
                }
                if (!send) {
                    try {
                        context.startActivity(intent)
                    } catch (unused2: Exception) {
                        unused2.printStackTrace()
                    }
                }
                if (pendingIntent != null) {
                    ExternalNotifyUtil.sendNotify(context, pendingIntent)
                }
            }, delayTime)
        }
    }

    private fun triggerAlarm(triggerTime: Long, pendingIntent: PendingIntent) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
        } else {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)
        }
    }

    /**
     * 小米和vivo都可以用
     */
    private fun startActivityBelowQ(intent: Intent): Boolean {
        val baseContext = baseContext ?: return false
        val newPkgName = "com.android.contacts"
        val backPkgName = baseContext.packageName // 备份原包名
        try {
            val field: Field = baseContext.javaClass.getDeclaredField("mBasePackageName")
            field.isAccessible = true;
            field.set(baseContext, newPkgName)
            baseContext.startActivity(intent) // 启动 Activity
            field.set(baseContext, backPkgName)
            return true
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 小米使用
     */
    @SuppressLint("PrivateApi")
    private fun reflectMiIntent(intent: Intent) {
        try {
            val method = intent.javaClass
                .getDeclaredMethod("addMiuiFlags", Int::class.javaPrimitiveType)
            method.isAccessible = true
            method.invoke(intent, 0x2)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    @SuppressLint("PrivateApi")
    private fun reflectVivoIntent(intent: Intent) {
        try {
            val method1 = intent.javaClass.getDeclaredMethod("setForceStart", Boolean::class.javaPrimitiveType)
            method1.isAccessible = true
            method1.invoke(intent, true)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        try {
            val method2 = intent.javaClass.getDeclaredMethod("setIsVivoWidget", Boolean::class.javaPrimitiveType)
            method2.isAccessible = true
            method2.invoke(intent, true)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun isNotificationEnable(context: Context): Boolean {
        val manager = NotificationManagerCompat.from(context)
        return manager.areNotificationsEnabled()
    }

    private fun checkAllowedBgPopupPermission(context: Context): Boolean {
        return Machine.isHuaWei() || (Machine.isXiaomi() && isXiaomiAllowedBgPopup(
            context)) || (Machine.isVivo() && isVivoAllowedBgPopup(
            context)) || (Machine.isOppo() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(
            context))
    }

    /**
     * 判断小米是否有后台弹出权限
     */
    private fun isXiaomiAllowedBgPopup(context: Context): Boolean {
        val ops =
            context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
        try {
            val op = 10021
            val method: Method = ops.javaClass.getMethod(
                "checkOpNoThrow", *arrayOf<Class<*>?>(
                    Int::class.javaPrimitiveType,
                    Int::class.javaPrimitiveType,
                    String::class.java
                )
            )
            val result =
                method.invoke(ops, op, Process.myUid(), context.packageName) as Int
            return result == AppOpsManager.MODE_ALLOWED
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 判断vivo后台弹出界面 1未开启 0开启
     * @param context
     * @return
     */
    private fun isVivoAllowedBgPopup(context: Context): Boolean {
        val packageName = context.packageName
        val uri2: Uri =
            Uri.parse("content://com.vivo.permissionmanager.provider.permission/start_bg_activity")
        val selection = "pkgname = ?"
        val selectionArgs = arrayOf(packageName)
        try {
            val cursor: Cursor? = context
                .contentResolver
                .query(uri2, null, selection, selectionArgs, null)
            if (cursor != null) {
                return if (cursor.moveToFirst()) {
                    val currentmode: Boolean = cursor.getInt(cursor.getColumnIndex("currentstate")) == 0
                    cursor.close()
                    currentmode
                } else {
                    cursor.close()
                    false
                }
            }
        } catch (throwable: Throwable) {
            throwable.printStackTrace()
        }
        return false
    }

    private class PendingActivityBean {
        var startProcessingTime = -1L
        var retryCount = 0
        var intent: Intent? = null
    }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
    }

    override fun onActivityStarted(activity: Activity) {
        activityMap.put(activity.hashCode(), activity.javaClass)
    }

    override fun onActivityResumed(activity: Activity) {
    }

    override fun onActivityPaused(activity: Activity) {
    }

    override fun onActivityStopped(activity: Activity) {
        activityMap.remove(activity.hashCode())
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
    }

    override fun onActivityDestroyed(activity: Activity) {
    }

    interface IPopupCallback {
        fun onPopupTouch()
        fun onPopupShown()
    }
}